﻿using System;
using System.Collections.Generic;
using System.Xml.Linq;
using System.Diagnostics;

namespace SoftwareLogistics.SharepointClient.Library.Models
{
    public class SPQuery
    {
        public SPQuery()
        {
            SubQueries = new List<SPQuery>();
            OrderByClause = new List<SPOrderBy>();
            Joins = new List<SPJoin>();
            ProjectedFields = new List<SPProjectedField>();
            IsDefault = false;
        }

        public bool IsDefault { get; set; }

        public enum QueryTypes
        {
            And,
            Or
        }

        public QueryTypes QueryType;
        
        public void AddAndClause(params SPWhereClause[] args)
        {
            Clauses = new List<SPWhereClause>();
            var subQuery = new SPQuery { Clauses = new List<SPWhereClause>(), QueryType = QueryTypes.And };
            foreach(var arg in args)
                subQuery.Clauses.Add(arg);

            SubQueries.Add(subQuery);            
        }

        public void AddOrClause(params SPWhereClause[] args)
        {
            Clauses = new List<SPWhereClause>();
            var subQuery = new SPQuery();
            subQuery.QueryType = QueryTypes.Or;
            foreach (var arg in args)
                subQuery.Clauses.Add(arg);

            SubQueries.Add(subQuery);
        }

        public void AddJoin(string list1, string list2, string pkey)
        {
            Joins.Add(new SPJoin(list1, list2, pkey));
        }

        public void AddJoin(string list2, string pkey)
        {
            throw new NotImplementedException();
            //Joins.Add(new SPJoin(list2, pkey));
        }

        public string Name { get; set; }
        public List<SPOrderBy> OrderByClause{ get; set; }
        public SPWhereClause WhereClause {get; set;}
        public List<SPWhereClause> Clauses { get; set; }
        public List<SPQuery> SubQueries { get; set; }
        public List<SPJoin> Joins { get; set; }
        public List<SPProjectedField> ProjectedFields { get; set; }

        public void AddProjectedField(string name, string list, string alias)
        {
            throw new NotImplementedException();
            //ProjectedFields.Add(new SPProjectedField(name, list, alias));
        }

        public string OrderBy { get; set; }

        public XElement GetSubqueryElement()
        {
            var element = new XElement(QueryType == QueryTypes.And ? "And" : "Or");
            Clauses.ForEach(ele => element.Add(ele.GetXML()));
            return element;
        }

        //TODO: Commented out code could potentially be added back in to do joins       
        public XElement GetElement()
        {
            if (WhereClause == null && SubQueries == null && OrderByClause == null)
                return null;

            var topLevel = new XElement("View");

            var queryElement = new XElement("Query");
            if (OrderByClause.Count > 0)
            {
                var orderByElement = new XElement("OrderBy");
                OrderByClause.ForEach(ele => orderByElement.Add(ele.GetXML()));
                queryElement.Add(orderByElement);
            }

            var whereElement = new XElement("Where");

            if(SubQueries != null)
                SubQueries.ForEach(ele => whereElement.Add(ele.GetSubqueryElement()));

            if (WhereClause != null)
                whereElement.Add(WhereClause.GetXML());

            queryElement.Add(whereElement);
            return queryElement;
            topLevel.Add(queryElement);
            return topLevel;

            /*
            if (Joins.Count > 0)
            {
                XElement joins = new XElement("Joins");
                Joins.ForEach(join => joins.Add(join.GetJoinElement()));

                topLevel.Add(joins);
            }

            if (ProjectedFields.Count > 0)
            {
                XElement projectedFields = new XElement("ProjectedFields");

                ProjectedFields.ForEach(field => projectedFields.Add(field.GetProjectedField()));

                topLevel.Add(projectedFields);
            }*/

            //return topLevel;
        }
    }
}
